import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Project } from "../entity/project.entity";
import { In, Repository } from "typeorm";
import { Stage } from "../entity/stage.entity";
import { StageFunding } from "../entity/stageFunding.entity";
import { InvestFunding, InvestFundingMinusType, InvestFundingPlusType } from "../entity/investFunding.entity";
import { InvestOrder } from "../entity/investOrder.entity";
import { StageInterest } from "../entity/stageInterest.entity";
import { StageFundingFlow } from "../entity/stageFundingFlow.entity";
import { InvestInterest } from "../entity/investInterest.entity";
import { Account } from "@/account/entity/account.entity";
import { StageService } from "./stage.service";
import { UserInvestmentummaryDto, UserSummaryDto } from "../dto/summary.dto";
import { InvestmentService } from "./investment.service";
import { InvestFundingType } from "../dto/investFunding.dto";
import { MoreThan, Not } from 'typeorm';
import { LessThanOrEqual, Raw } from 'typeorm';
import { Brackets } from 'typeorm';

@Injectable()
export class SummaryService {
  constructor(
    @InjectRepository(Project)
    private projectRepository: Repository<Project>,
    @InjectRepository(Stage)
    private stageRepository: Repository<Stage>,
    @InjectRepository(StageFunding)
    private stageFundingRepository: Repository<StageFunding>,
    @InjectRepository(InvestFunding)
    private investFundingRepository: Repository<InvestFunding>,
    @InjectRepository(InvestOrder)
    private investOrderRepository: Repository<InvestOrder>,
    @InjectRepository(StageInterest)
    private readonly stageInterestRepo: Repository<StageInterest>,
    @InjectRepository(StageFundingFlow)
    private readonly flowRepo: Repository<StageFundingFlow>,
    @InjectRepository(InvestInterest)
    private readonly investInterestRepo: Repository<InvestInterest>,
    @InjectRepository(Account)
    private accountRepository: Repository<Account>,
    private investmentService: InvestmentService,
    private stageService: StageService,
  ) {}

  async getTotalIncome(userId: number, startDate: Date, endDate: Date): Promise<number> {
    const res = await this.investInterestRepo.createQueryBuilder('ii')
    .leftJoinAndSelect('ii.stage', 'stage')
    .select('sum(money) as pnl')
    .where('ii.investorId = :userId', {userId})
    .andWhere('date >= :date1', {date1: startDate})
    .andWhere('date <= :date2', {date2: endDate})
    .andWhere('stage.investmentStatus != :status', { status: 4 })
    .getRawOne();
    return res.pnl ? parseFloat(res.pnl) : 0;
  }

  async getTotalMoney(userId: number, type: InvestFundingPlusType|InvestFundingMinusType): Promise<number> {
    const res = await this.investFundingRepository.createQueryBuilder('ii')
    .leftJoinAndSelect('ii.stage', 'stage')
    .select('sum(value) as value')
    .where('ii.investorId = :userId', {userId})
    .andWhere('type = :type', {type})
    .andWhere('stage.investmentStatus != :status', { status: 4 })
    .getRawOne();
    return res.value ? parseFloat(res.value) : 0;
  }

  async getInvestSum(userId: number) {
    const investMoney = await this.getTotalMoney(userId, InvestFundingPlusType.INVESTMENT);
    const investDistMoney = await this.getTotalMoney(userId, InvestFundingPlusType.INTEREST_DISTRIBUTION);
    const taxMoney = await this.getTotalMoney(userId, InvestFundingPlusType.TAX_WITHOLDING);
    const manageMoney = await this.getTotalMoney(userId, InvestFundingPlusType.MANAGEMENT_CHARGE);
    const withdrawMoney = await this.getTotalMoney(userId, InvestFundingMinusType.WITHDRAWAL);
    const principal = investMoney - withdrawMoney;
    const totalAsset = investMoney + investDistMoney + taxMoney + manageMoney;
    return {
        principal,
        totalAsset
    }
  }

  private async getEarnReceived(userId: number) {
    // 获取今天的结束时间（明天00:00）
    const now = new Date();
    const endOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);


    const earningsReceived = await this.investFundingRepository.createQueryBuilder('investFunding')
    .leftJoinAndSelect('investFunding.stage', 'stage')
    .select('SUM(investFunding.value)', 'total')
    .where('investFunding.investor_id = :userId', { userId})
    .andWhere('type in (:types)', {types: [
          InvestFundingPlusType.INTEREST_DISTRIBUTION]})
    .andWhere('investFunding.end_date < :endDate', {endDate: endOfToday})
    .andWhere('stage.investmentStatus != :status', { status: 4 })
    .getRawOne();
    return earningsReceived.total
  }

  async brief(user: Account): Promise<UserSummaryDto> {
    const now = new Date();
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const lastDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
    const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
    const startOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
    const endOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0);
    const startOfYear = new Date(now.getFullYear(), 0, 1);
    const lastDayIncome = await this.getTotalIncome(user.id, lastDay, today);
    const lastMonthIncome = await this.getTotalIncome(user.id, startOfLastMonth, endOfLastMonth);
    const thisMonthIncome = await this.getTotalIncome(user.id, startOfMonth, today);
    const thisYearIncome = await this.getTotalIncome(user.id, startOfYear, today);
    const {principal, totalAsset}  = await this.getInvestSum(user.id);
    const myEarnings = await this.investmentService.getUserEarn(user.id)
    return {
        userIncome:{
            myEarnings,
            earningsReceived: await this.getEarnReceived(user.id),
            lastDay: lastDayIncome,
            lastMonth: lastMonthIncome,
            thisMonth: thisMonthIncome,
            thisYear: thisYearIncome,
            money: totalAsset,
            principal: principal,
        },
        team: []
    }
  }

  // 获取用户未发放的收益
  private async getUserUnclaimEarn(userId: number) {
    const now = new Date();
    const res = await this.investInterestRepo.createQueryBuilder('ii')
    .leftJoinAndSelect('ii.stage', 'stage')
    .select('sum(money) as pnl')
    .where('ii.investor_id = :userId', {userId})
    .andWhere('date < :date2', {date2: now})
    .andWhere('stage.investmentStatus != :status', { status: 4 })
    .getRawOne();

    const pnlUtilToday = res.pnl ? parseFloat(res.pnl) : 0;
    const fundingRes = await this.investFundingRepository.createQueryBuilder('investFunding')
    .select('SUM(investFunding.value)', 'total')
    .where('investFunding.investor_id = :userId', { userId})
    .andWhere('type in (:types)', {types: [InvestFundingPlusType.MANAGEMENT_CHARGE,
      InvestFundingPlusType.TAX_WITHOLDING,
      InvestFundingPlusType.INTEREST_DISTRIBUTION]})
    .andWhere('investFunding.end_date < :date2', {date2: now})
    .getRawOne();
    return pnlUtilToday - fundingRes.total;
  }

  async investment(user: Account): Promise<UserInvestmentummaryDto> {
    const now = new Date();
    const begin = new Date(now.getFullYear()-20, 1, 1);
    const end = new Date(now.getFullYear()+20, 1, 1);
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const lastDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
    const startOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
    const endOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0);
    // 计算当前财年的开始和结束日期
    const currentYear = now.getMonth() < 6 ? now.getFullYear() : now.getFullYear() + 1;
    const startOfFinancialYear = new Date(currentYear - 1, 6, 1); // 上一年的7月1日
    const endOfFinancialYear = new Date(currentYear, 5, 30); // 当年的6月30日

    // 计算上一财年的开始和结束日期
    const startOfLastFinancialYear = new Date(currentYear - 2, 6, 1); // 再上一年的7月1日
    const endOfLastFinancialYear = new Date(currentYear - 1, 5, 30); // 上一年的6月30日

    const interestEarnedYesterday = await this.getTotalIncome(user.id, lastDay, today);
    const interestEarnedLastMonth = await this.getTotalIncome(user.id, startOfLastMonth, endOfLastMonth);
    const interestEarnedThisYear = await this.getTotalIncome(user.id, startOfFinancialYear, now);
    const interestEarnedLastYear = await this.getTotalIncome(user.id, startOfLastFinancialYear, endOfLastFinancialYear);
    const interestUtilTody = await this.getTotalIncome(user.id, begin, today);
    const interestEarnedTotal = await this.getTotalIncome(user.id, begin, now);
    const {principal}  = await this.getInvestSum(user.id);
    
    // 计算总资产：本金 + 截止到今天的利息，已经去掉了提取的本金
    const totalAsset = principal + interestUtilTody;

    return {
        totalAsset,
        principal,
        interestEarnedYesterday, 
        interestEarnedLastMonth,
        interestEarnedThisYear,
        interestEarnedLastYear,
        interestEarnedTotal,
        accruedInterest: await this.getUserUnclaimEarn(user.id),
    } 
  }

  async stage(user: Account, status?: string) {
    const investOrder = await this.investFundingRepository.find({
      where: {
        investorId: user.id,
      }
    });
    const stageOrders = investOrder.map((item) => item.stageId);
    // 对stageId进行去重处理
    const stageIds = [...new Set(stageOrders)];
    const where = { 
      id: In(stageIds)
    };
    
    // 获取今天的结束时间（明天00:00）
    const now = new Date();
    const endOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);

    let stages = [];

    // 根据status参数筛选不同的investmentStatus值
    if (status) {
      if (status === 'subscription') {
        // 判断loanstartdate大于今天的日期
  
        // 使用queryBuilder重写查询
        stages = await this.stageRepository.createQueryBuilder('stage')
          .where('stage.id IN (:...stageIds)', { stageIds })
          .andWhere('stage.investmentStatus != :status', { status: '4' })
          .andWhere('stage.loanStartDate > :endOfToday', { endOfToday })
          .leftJoinAndSelect('stage.project', 'project')
          .getMany();
      } else if (status === 'completed') {
         
        // 使用查询构建器实现OR条件筛选
        const queryBuilder = this.stageRepository.createQueryBuilder('stage')
          .leftJoinAndSelect('stage.project', 'project')
          .where('stage.id IN (:...stageIds)', { stageIds }) 
          .andWhere('stage.loanStartDate <= :endOfToday', { endOfToday })
          .andWhere('stage.investmentStatus != :status', { status: 4 })
          .andWhere(new Brackets(qb => {
            // 条件1: Loan Repayment Date小于等于今天
            qb.where('stage.loanRepaymentDate <= :endOfToday', { endOfToday })
              // 条件2: 存在最新的WITHDRAWAL事件且日期小于等于今天
              .orWhere(
                `EXISTS (
                  SELECT 1 FROM invest_funding inv_fund
                  WHERE inv_fund.investor_id = :userId
                  AND inv_fund.type = :withdrawType
                  AND inv_fund.stage_id = stage.id
                  AND inv_fund.transcation_date <= :endOfToday
                  AND inv_fund.transcation_date = (
                    SELECT MAX(iaf.transcation_date)
                    FROM invest_funding iaf
                    WHERE iaf.investor_id = :userId
                    AND iaf.type = :withdrawType
                    AND iaf.stage_id = stage.id
                  )
                )`,
                {
                  userId: user.id,
                  withdrawType: InvestFundingMinusType.WITHDRAWAL,
                  endOfToday
                }
              );
          }));
        
        stages = await queryBuilder.getMany();

      } else {
        
        // status = performing判断条件
        const queryBuilder = this.stageRepository.createQueryBuilder('stage')
          .leftJoinAndSelect('stage.project', 'project')
          .where('stage.id IN (:...stageIds)', { stageIds })
          .andWhere('stage.investmentStatus != :status', { status: 4 })
          .andWhere('stage.loanStartDate <= :endOfToday', { endOfToday })
          .andWhere(new Brackets(qb => {
            // 条件1: Loan Repayment Date大于今天
            qb.where('stage.loanRepaymentDate > :endOfToday', { endOfToday })
              // 或者Loan Repayment Date为空
              .orWhere('stage.loanRepaymentDate IS NULL');
          }))
          .andWhere(new Brackets(qb => {
            // 条件2: 不存在最新的WITHDRAWAL事件或事件日期大于今天
            qb.where(
              `NOT EXISTS (
                SELECT 1 FROM invest_funding inv_fund
                WHERE inv_fund.investor_id = :userId
                AND inv_fund.type = :withdrawType
                AND inv_fund.stage_id = stage.id
                AND inv_fund.transcation_date <= :endOfToday
                AND inv_fund.transcation_date = (
                  SELECT MAX(iaf.transcation_date)
                  FROM invest_funding iaf
                  WHERE iaf.investor_id = :userId
                  AND iaf.type = :withdrawType
                  AND iaf.stage_id = stage.id
                )
              )`,
              {
                userId: user.id,
                withdrawType: InvestFundingMinusType.WITHDRAWAL,
                endOfToday
              }
            );
          }));

        stages = await queryBuilder.getMany();
      }
    }
    
    // const stages = await this.stageRepository.find({where, relations: ['project']})
    const res = []
    for(const item of stages) {
      const investMoney = await this.stageService.getUserInvestRemainMoney(item.id, user.id)
      
      // 新增: 当status为completed时，获取用户最后一次WITHDRAWAL的金额和时间，以及第一次投资的时间
      let lendingAmount = investMoney;
      let userLoanStartDate = item.loanStartDate; // 默认使用项目阶段的开始时间
      let userLoanEndDate = item.loanRepaymentDate; // 默认使用项目阶段的结束时间
      
      if (status === 'completed') {
        // 获取最后一次WITHDRAWAL记录
        const lastWithdrawal = await this.investFundingRepository
          .createQueryBuilder('investFunding')
          .select('value, transcation_date')
          .where('stage_id = :stageId', { stageId: item.id })
          .andWhere('investor_id = :userId', { userId: user.id })
          .andWhere('type = :type', { type: InvestFundingMinusType.WITHDRAWAL })
          .andWhere('transcation_date is not null')
          .orderBy('transcation_date', 'DESC')
          .limit(1)
          .getRawOne();
        
        // 获取第一次投资记录（假设投资类型为INVEST）
        const firstInvestment = await this.investFundingRepository
          .createQueryBuilder('investFunding')
          .select('transcation_date')
          .where('stage_id = :stageId', { stageId: item.id })
          .andWhere('investor_id = :userId', { userId: user.id })
          .andWhere('type = :type', { type: InvestFundingPlusType.INVESTMENT })
          .andWhere('transcation_date is not null')
          .orderBy('transcation_date', 'ASC')
          .limit(1)
          .getRawOne();
        
        // 如果存在最后一次提现记录，则更新相应字段
        if (lastWithdrawal) {
          lendingAmount = lastWithdrawal.value;
          userLoanEndDate = new Date(lastWithdrawal.transcation_date);
        }
        
        // 如果存在第一次投资记录，则更新开始时间
        if (firstInvestment) {
          userLoanStartDate = new Date(firstInvestment.transcation_date);
        }
      }
      
      const interestPaid = await this.investFundingRepository.
        createQueryBuilder('investFunding').
        select('sum(value)', 'value').
        where("stage_id = :stageId and transcation_date is not null", {stageId: item.id}).
        andWhere('investor_id = :userId', {userId: user.id}).
        andWhere('type = :type', {type: InvestFundingPlusType.INTEREST_DISTRIBUTION}).
        getRawOne();
      const earnReceived = await this.investFundingRepository.
        createQueryBuilder('investFunding').
        select('sum(value)', 'value').
        where("stage_id = :stageId", {stageId: item.id}).
        andWhere('investor_id = :userId', {userId: user.id}).
        andWhere('type = :type', {type: InvestFundingPlusType.INTEREST_DISTRIBUTION}).
        andWhere('end_date < :endDate', {endDate: endOfToday}).
        getRawOne();
      const accruedInterest = await this.investFundingRepository.
        createQueryBuilder('investFunding').
        select('sum(value)', 'value').
        where("stage_id = :stageId and transcation_date is null", {stageId: item.id}).
        andWhere('investor_id = :userId', {userId: user.id}).
        andWhere('type = :type', {type: InvestFundingPlusType.INTEREST_DISTRIBUTION}).
        getRawOne();
      const totalTargetReturn = await this.investFundingRepository.
        createQueryBuilder('investFunding').
        select('sum(value)', 'value').
        where("stage_id = :stageId", {stageId: item.id}).
        andWhere('investor_id = :userId', {userId: user.id}).
        andWhere('type = :type', {type: InvestFundingPlusType.INTEREST_DISTRIBUTION}).
        getRawOne();
      // 计算上个月日期范围
      const now = new Date();
      const startOfLastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
      const endOfLastMonth = new Date(now.getFullYear(), now.getMonth(), 0);
      
      // 计算上个月该阶段利息（仅当前用户）
      const lastMonthInterest = await this.investInterestRepo
        .createQueryBuilder('ii')
        .select('sum(money) as pnl')
        .where('ii.stageId = :stageId', {stageId: item.id})
        .andWhere('ii.investorId = :userId', {userId: user.id})  // 添加用户筛选
        .andWhere('date >= :startDate', {startDate: startOfLastMonth})
        .andWhere('date <= :endDate', {endDate: endOfLastMonth})
        .getRawOne();
      
      res.push({
        stageId: item.id,
        name: item.project.name,
        loanExpiryDay: item.loanRepaymentDate, // 此处暂时使用endDate字段
        LVR: item.LVR,
        lendingAmount: lendingAmount,
        rateOfNetReturn: item.interestRate,
        interestPaid: interestPaid.value,
        accruedInterest: accruedInterest?.value,
        totalTargetReturn: totalTargetReturn.value,
        loanStartDate: userLoanStartDate, // 修改为使用用户特定的开始时间
        loanEndDate: userLoanEndDate, // 修改为使用用户特定的结束时间
        loanTerm: item.loanTerm,
        earnReceived: earnReceived.value,
        lastMonthInterest: lastMonthInterest.pnl ? parseFloat(lastMonthInterest.pnl) : 0
      })
    }
    return res
  }

  async interest(user: Account, projectId: number, stageId?: number) {
    // 构建查询条件
    const queryBuilder = this.investFundingRepository.createQueryBuilder('investFunding')
      .leftJoinAndSelect('investFunding.stage', 'stage')
      .leftJoinAndSelect('stage.project', 'project')
      .where('investFunding.investorId = :userId', { userId: user.id })
      .andWhere('investFunding.type = :type', { type: InvestFundingPlusType.INTEREST_DISTRIBUTION })
      .andWhere('stage.investmentStatus != :status', { status: 4 });
    
    // 添加可选的过滤条件
    if (projectId) {
      queryBuilder.andWhere('stage.projectId = :projectId', { projectId });
    }
    
    if (stageId) {
      queryBuilder.andWhere('investFunding.stageId = :stageId', { stageId });
    }
    
    // 执行查询
    const interestDistributions = await queryBuilder.getMany();
    
    // 转换为所需的返回格式
    const result = interestDistributions.map(item => {
      return {
        // date: item.transcationDate || item.startDate, // 使用交易日期，如果没有则使用开始日期
        date: item.endDate,
        interest: item.value, // 使用value字段作为interest值
        project: item.stage.project.name // 项目名称
      };
    });
    
    // 按日期排序
    return result.sort((a, b) => a.date.getTime() - b.date.getTime());
  }

  async fundDay(user: Account, stageId: number, type: string) {
    // let interests: InvestInterest[] = []
    // if (stageId) {
    //   interests = await this.investInterestRepo.find({where: {stageId, investorId:  user.id}, order: {date: 'DESC'}})
    // } else {
    //   interests = await this.investInterestRepo.find({where: {investorId:  user.id}, order: {date: 'DESC'}})
    // }
    let fundingType = []
    if (type) {
      fundingType = [type]
    } else {
     fundingType = [
        InvestFundingPlusType.INVESTMENT, 
        InvestFundingMinusType.WITHDRAWAL, 
        InvestFundingPlusType.INTEREST_DISTRIBUTION,
        InvestFundingPlusType.MANAGEMENT_CHARGE,
        InvestFundingPlusType.TAX_WITHOLDING,
      ]
    }
    const where = {type: In(fundingType), investorId: user.id}
    if(stageId) {
      where['stageId'] = stageId
    }
    // 添加时间限制，只获取截止到当前时间的事件
    const now = new Date();
    
    // 使用 QueryBuilder 以便添加时间限制条件
    let query = this.investFundingRepository.createQueryBuilder('investFunding')
      .leftJoinAndSelect('investFunding.stage', 'stage')
      .andWhere('stage.investmentStatus != :status', { status: 4 })
      .leftJoinAndSelect('stage.project', 'project')
      .where('investFunding.investorId = :investorId', { investorId: user.id })
      .andWhere('investFunding.type IN (:...types)', { types: fundingType })
      .andWhere('investFunding.startDate <= :now', { now })
      .orderBy('investFunding.startDate', 'DESC');
    
    if (stageId) {
      query = query.andWhere('investFunding.stageId = :stageId', { stageId });
    }
    
    const fundings = await query.getMany();
    const res: Record<string, InvestFunding[]> = {}
    for(const item of fundings) {
      const dateStr = item.startDate.getFullYear() + '-' + (item.startDate.getMonth() + 1) + '-' + item.startDate.getDate()
      if (!res[dateStr]) {
        res[dateStr] = []
      }
      item['name'] = item.stage.project.name
      delete item['stage']
      res[dateStr].push(item)
    }
    return res
  }
}